package com.spc.boot.controller;
import cn.hutool.crypto.asymmetric.KeyType;
import cn.hutool.crypto.asymmetric.RSA;
import com.spc.boot.common.security.CustomUserDetailsService;
import com.spc.boot.common.security.entity.DbUser;
import com.spc.boot.common.security.entity.Principal;
import com.spc.boot.common.security.entity.ResultMap;
import com.spc.boot.common.security.mapper.SecurityMapper;
import com.spc.boot.common.util.JsonUtil;
import com.spc.boot.common.util.StringUtil;
import com.spc.boot.common.util.TokenUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.WebAuthenticationDetails;
import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken;
import org.springframework.security.web.csrf.CsrfToken;
import org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.util.Date;
import java.util.Objects;

@Controller
@Slf4j
public class LoginController {


    @Value("${rsa.private}")
    private String rsaPrivateKey;

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Autowired
    private SecurityMapper securityMapper;

    @Autowired
    CustomUserDetailsService customUserDetailsService;

    @GetMapping("/account/login")
    public String login(){

        Authentication authInfo = SecurityContextHolder.getContext().getAuthentication();

        if(!Objects.isNull(authInfo) && !Objects.isNull(authInfo.getPrincipal())){
            //已登陆成功的实体用户,重定向到根目录,匿名用户则继续返回到login页面
            if(authInfo.isAuthenticated()
                    && !"anonymousUser"
                    .equals(authInfo.getPrincipal() instanceof String ? authInfo.getPrincipal() : "otherUser")){
                return "redirect:/";
            }
        }

        return "account/login";
    }

    @PostMapping("/account/apiLogin")
    @ResponseBody
    public ResultMap apiLogin(HttpServletRequest request,String principal, String code, String activationCode, Long activationTime) {

        //解密
        RSA rsa = new RSA(rsaPrivateKey, null);
        Principal principalObj = JsonUtil.deserialize(rsa.decryptStr(principal, KeyType.PrivateKey), Principal.class);

        ResultMap result = new ResultMap();
        if (StringUtil.isBlank(principalObj.getUsername())) {
            result.setMessage("请输入账号");
            return result;
        }
        if (StringUtil.isBlank(principalObj.getPassword())) {
            result.setMessage("请输入密码");
            return result;
        }

        // 根据验证码类型配置进行相应处理
       /* if ("default".equals(captchaType)) {
            String servercode = (String) request.getSession().getAttribute(VerifyCodeFilter.LOGIN_VERIFY_CODE_KEY);
            if (servercode != null && servercode.length() > 0) {
                if (StringUtil.isBlank(code)) {
                    result.setMessage("请输入验证码");
                    return result;
                }
                if (!servercode.equalsIgnoreCase(code)) {
                    // 验证码错误
                    request.getSession().removeAttribute(VerifyCodeFilter.LOGIN_VERIFY_CODE_KEY);
                    result.setMessage("验证码错误");
                    return result;
                }
            }
        } else if ("puzzle".equals(captchaType)) {
            long validTime = 1000 * 60L;
            if (activationTime == null || (System.currentTimeMillis() - activationTime) > validTime) {
                result.setMessage("激活码已过期，请重新验证");
                return result;
            }
            String cacheActivationCode = (String) request.getSession()
                    .getAttribute(PuzzleCaptchaUtil.LOGIN_PUZZLE_VERIFY_CODE_VERIFY_SUCCESS_KEY);
            request.getSession().removeAttribute(PuzzleCaptchaUtil.LOGIN_PUZZLE_VERIFY_CODE_VERIFY_SUCCESS_KEY);
            if (StringUtil.isEmpty(cacheActivationCode) || !cacheActivationCode.equals(activationCode)) {
                result.setMessage("激活码校验失败，请重新验证");
                return result;
            }
        } else {
            result.setMessage("当前验证码类型【" + captchaType + "】未实现");
            return result;
        }*/

        DbUser user = securityMapper.selectUserByLoginId(principalObj.getUsername());
        if (user == null) {
            result.setMessage("用户不存在");
            return result;
        }
        if (!user.getIsEnabled()) {
            result.setMessage("用户已禁用");
            return result;
        }
        UserDetails userDetails = customUserDetailsService.loadUserByUsername(user.getLoginId());
        DbUser dbUser = (DbUser) request.getAttribute("dbUser");
        if (null != dbUser) {
            if (dbUser.getIsLocked()) {
                result.setMessage("用户已锁定");
                return result;
            }
            user.setIsLocked(dbUser.getIsLocked());
            user.setAttemptLoginTimes(dbUser.getAttemptLoginTimes());
            user.setLastAttemptDate(dbUser.getLastAttemptDate());
            user.setLockChangeDate(dbUser.getLockChangeDate());
        }

        if (!passwordEncoder.matches(principalObj.getPassword(), user.getPassword())) {
            /*Integer loginTimes = dbUser.getAttemptLoginTimes() + 1;
            user.setAttemptLoginTimes(loginTimes);
            if (loginTimes >= LoginListener.LOGIN_ERROR_MAX_COUNT) {
                // 锁定账户
                user.setIsLocked(true);
                user.setLockChangeDate(new Date());
            }
            securityMapper.updateUser(user);*/
            result.setMessage("密码不正确");
            return result;
        }

        //账户登录核心逻辑
        PreAuthenticatedAuthenticationToken authentication = new PreAuthenticatedAuthenticationToken(userDetails,
                userDetails.getPassword(), userDetails.getAuthorities());
        authentication.setDetails(new WebAuthenticationDetails(request));
        SecurityContextHolder.getContext().setAuthentication(authentication);

        //返回token
        String authToken = TokenUtils.createToken(user.getLoginId(), user.getPassword());
        result.getParameters().put("authToken", authToken);

      /*  // 将token生成时间放入缓存
        Cache cache = ehCacheManager.getCacheManager().getCache("oauth");
        Element ele = new Element(authToken, System.currentTimeMillis());
        cache.put(ele);

        // 将csrfToken返回客户端
        HttpSessionCsrfTokenRepository csrfTokenRepository = new HttpSessionCsrfTokenRepository();
        CsrfToken csrfToken = csrfTokenRepository.loadToken(request);
        if (csrfToken == null) {
            csrfToken = csrfTokenRepository.generateToken(request);
            csrfTokenRepository.saveToken(csrfToken, request, response);
        }
        result.getParameters().put("csrfToken", csrfToken.getToken());*/

        result.setMessage("登录成功！");
        result.setSuccess(true);

        // 记录登录日志
        log.info("登录系统成功！");
        /*if (user != null) {
            user.setLoginCount(user.getLoginCount() + 1);
            user.setLastLoginDate(new Date());
            user.setLastLoginIp(request.getRemoteAddr());
            user.setAttemptLoginTimes(0);
            securityMapper.updateUser(user);
        }*/
        return result;
    }

    //登出操作
    @PostMapping("/account/logout")
    @ResponseBody
    public String logout(HttpServletRequest request){

            SecurityContextHolder.clearContext();
            HttpSession session = request.getSession(false);
            if (session != null) {
                session.invalidate();
            }
            log.info("退出系统成功！");

        //登出成功返回登录页面
        return "account/login";
    }

    @PostMapping("/account/apiLogout")
    @ResponseBody
    public ResultMap apiLogout(HttpServletRequest request) {
        ResultMap result = new ResultMap();
        SecurityContextHolder.clearContext();
        HttpSession session = request.getSession(false);
        if (session != null) {
            session.invalidate();
        }
        log.info("退出系统成功！");
        return result;
    }
}